/*
 * 描述： <描述>
 * 修改人： rain
 * 修改时间： 2016年01月20日
 * 项目： rainhy-cores-webcore
 */
package com.rainhy.webcore.util;

import java.io.Serializable;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.id.AbstractUUIDGenerator;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.UUIDHexGenerator;

import com.rainhy.RainhyConstant;
import com.rainhy.core.exception.RainhyException;
import com.rainhy.core.util.ComputerUtils;
import com.rainhy.core.util.RandomUtils;

/**
 * 生成UUID唯一键工具类
 * 
 * @author brady
 * @version [版本号, 2013-8-27]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class UUIDUtils {
    
    public static class UUID16HexGenerator extends AbstractUUIDGenerator {
        
        private static int count = 0;
        
        private static int MAX_COUNT = Integer.parseInt("zzzz", 36);
        
        private static String LEFT_PAD = RandomUtils.nextString(RainhyConstant.COMMON_STRING_CHAR_LOWER, 6);    // 在极限情况下,会生成9位的 uuid, 时间戳1位(0),IP地址5位,自增长4位
        
        public UUID16HexGenerator() {
            super();
        }
        
        @Override
        public Serializable generate(SessionImplementor session, Object obj) {
            // IP地址,36进制,5-7位
            // 时间戳(单位毫秒),36进制,6位
            // 同时间调用的自增长数字 36进制(zzzz,1679615) - 4位
            // 总长度为 15~17(不够,用随机数补位,过长,则截取后面16位)
            
            long currentTimeMillis = System.currentTimeMillis();
            String str1 = Long.toString(getHostAddressBy36(), 36); // IP地址,32进制,5-7位
            String str2 = Long.toString(currentTimeMillis / 1000, 36); // 时间戳(单位毫秒),32进制,6位
            String str3 = StringUtils.leftPad(Long.toString(count(), 36), 4, '0'); // 同时间调用的自增长数字 32进制(zzzz,1679615) - 4位
            StringBuilder sb = new StringBuilder(32);
            if (sb.length() < 16) {
                sb.append(LEFT_PAD);
            }
            sb.append(str1).append(str2).append(str3);
            return StringUtils.right(sb.toString(), 16);
        }
        
        private int count() {
            synchronized (UUID16HexGenerator.class) {
                if (count > MAX_COUNT) {
                    count = 0;
                }
                return count++;
            }
        }
        
        private long getHostAddressBy36() {
            String addr = "127.0.0.1";
            try {
                addr = ComputerUtils.getLocalHostAddress();
            } catch (UnknownHostException e) {
                throw new RainhyException(e, "本机网络地址获取错误 : " + e.getMessage());
            }
            StringBuilder sb = new StringBuilder();
            String[] split = addr.split("\\.");
            for (String string : split) {
                sb.append(StringUtils.leftPad(Integer.toString(Integer.parseInt(string), 16), 2, '0'));
            }
            
            return Long.parseLong(sb.toString(), 16);
        }
    }
    
    private static final IdentifierGenerator generator = new UUIDHexGenerator();
    
    private static final IdentifierGenerator generator16 = new UUID16HexGenerator();
    
    //0-9共含有10个字符
    private static final Map<Integer, Character> integer2characterMap = new HashMap<Integer, Character>();
    
    static {
        //48为'0',57为'9'  0-9 10个
        for (int i = 0; i < 10; i++) {
            integer2characterMap.put(i, (char) ((int) '0' + i));
        }
        //97为'A-Z' 122为'z' 共26个字母  共36个
        for (int i = 0; i < 26; i++) {
            integer2characterMap.put(i + 10, (char) ((int) 'A' + i));
        }
        //
        for (int i = 0; i < 32; i++) {
            integer2characterMap.put(i + 36, (char) ((int) 'À' + i));
        }
    }
    
    /**
     * 利用 hibernate UUID生成器，生成唯一键 <功能详细描述>
     * 
     * @return String [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see org.hibernate.id.UUIDHexGenerator#generate(SessionImplementor, Object)
     */
    public static String generateUUID() {
        return generator.generate(null, null).toString();
    }
    
    /**
     * 
     * 根据 hibernate UUID生成器规则,实现16位唯一建
     *
     * @return String [返回类型说明]
     * @exception [异常类型] [异常说明]
     * @see com.rainhy.webcore.util.UUIDUtils.UUID16HexGenerator#generate(SessionImplementor, Object)
     * @version [版本号, 2016年9月15日]
     * @author rain
     */
    public static String generateUUID16() {
        return generator16.generate(null, null).toString();
    }
    
    /**
     * 
     * 根据 java 的 uuid 生成规则,生成唯一建
     *
     * @return String [返回类型说明]
     * @exception [异常类型] [异常说明]
     * @see java.util.UUID#randomUUID()
     * @version [版本号, 2016年9月15日]
     * @author rain
     */
    public static String generateUUIDjdk() {
        return StringUtils.replace(UUID.randomUUID().toString(), "-", "");
    }
    
    public static void main(String[] args) {
        //        System.out.println(Integer.parseInt("zzzz", 36));
        //        System.out.println(Long.toString(System.currentTimeMillis() / 1000, 36));
        System.out.println(Long.parseLong("01000001", 16));
        System.out.println(Long.toString(16777217L, 32));
        
        System.out.println(Long.parseLong("ffffffff", 16));
        System.out.println(Long.toString(4294967295L, 32));
        
        System.out.println(System.currentTimeMillis() >>> 32);
        //        System.out.println(Long.toString(16777216L, 36));
        //        System.out.println(str);
        //        str = Long.parseLong("73737373", 36);
        //        System.out.println(str);
        //        str = Long.toString(255255255255L, 10);
        //        System.out.println(str);
        
        //        UUIDUtils.generateUUID();
        //        UUIDUtils.generateUUID16();
        //        
        //        for (int i = 0; i <= 255; i++) {
        //            System.out.println((char) i + " : " + (i));
        //        }
        //        
        //        System.out.println("-----------------");
        //        
        //        for (Entry<Integer, Character> entry : integer2characterMap.entrySet()) {
        //            System.out.println(entry.getKey() + " : " + entry.getValue());
        //        }
    }
}
